#include <vcl.h>
#include <winuser.h>
#pragma hdrstop

#include <EIC.h>
#include "MTAG_CtrlStd.h"
#include "CStrGrid.h"
#include "uNombre.h"
#pragma package(smart_init)


#define MODULE_TAG MTAG_CSTRINGGRID

//---------------------------------------------------------------------------
// ValidCtrCheck est utilisé pour être sûr que les composants créés ne
// contiennent aucune fonction virtuelle pure.
//
__fastcall CIn::CIn(Classes::TComponent* AOwner):TInplaceEdit(AOwner)
    {
    }


///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

__fastcall CInNum::CInNum(Classes::TComponent* AOwner):TInplaceEdit(AOwner)
    {
    FColorNeg           = clRed;
    FMask               = "############.##";
    FMin                = 0;
    FMax                = MAXMAX;
    FNSActive           = false;
    FTypeVal            = eCurrency;
    FValeur             = 0;
    ValNS               = D_NS;
    inherited::Text     = "0";
    bIsNumValid         = true;
    }


//////////////////////////////////////
//
// SetMask
//
// Fonction: Initialise le Mask de saisie
//
// P.E.: Le Mask
//
// P.S.: AUCUN
//
//////////////////////////////////////
void __fastcall CInNum::SetMask( const AnsiString aMask )
    {
    int         i       = 0;
    AnsiString  aTmp;
    int         Pos;
    int         iNbEntiers;
    int         iNbDecim;

    FMask = aMask;

    try
        {
        aTmp.Insert( aMask,0 );

        while( i < aTmp.Length())
            {
            if( aTmp.c_str()[i] != SEP_DEC && aTmp.c_str()[i] != SEP_DEC_2 )
                aTmp.c_str()[i] = '9';
            if( aTmp.c_str()[i] == SEP_DEC_2 || aTmp.c_str()[i] == SEP_DEC )
            aTmp.c_str()[i] = DecimalSeparator;
            i ++;
            }

        if( aTmp.Length() != 0 )
            {
            FMax        = aTmp.ToDouble();
            MaxLength   = aTmp.Length();
            }
        else
            {
            SetTypeVal( FTypeVal );
            MaxLength = 0;
            }

        DecompNum( aTmp, iNbEntiers, iNbDecim, Pos );

        // Pt decimal existe
        if( Pos != 0 && FTypeVal != eFloat && FTypeVal != eDouble && FTypeVal != eCurrency )
            TypeValeur = eDouble;
        }
        
    catch( Exception &e )
        {
        EICDisplayException( TAG(10), e );
        }
    }



//////////////////////////////////////
//
// SetMax
//
// Fonction: Initialise Max
//
// P.E.: Max
//
// P.S.: AUCUN
//
//////////////////////////////////////
void __fastcall CInNum::SetMax( double dMax )
    {
    int         i       = 0;
    AnsiString  aTmp;

    aTmp = Mask;

    try
        {
        while( i < aTmp.Length())
            {
            if( aTmp.c_str()[i] != SEP_DEC && aTmp.c_str()[i] != SEP_DEC_2 )
                aTmp.c_str()[i] = '9';
            if( aTmp.c_str()[i] == SEP_DEC_2 || aTmp.c_str()[i] == SEP_DEC )
            aTmp.c_str()[i] = DecimalSeparator;
            i ++;
            }
        if( !aTmp.IsEmpty() && dMax > aTmp.ToDouble())
            FMax = aTmp.ToDouble();
        else
            FMax = dMax;
        }
        
    catch( Exception &e )
        {
        EICDisplayException( TAG(20), e );
        }
    }



//////////////////////////////////////
//
// SetMaxLength
//
// Fonction: Initialise la longueur Max du Num
//
// P.E.: MaxLength( non pris en compte )
//
// P.S.: AUCUN
//
//////////////////////////////////////
void __fastcall CInNum::SetMaxLength( signed int iMaxLength )
    {
    try
        {
        if( Mask.IsEmpty())
            inherited::MaxLength = MAXMASK;
        else
            {
            inherited::MaxLength = Mask.Length();
            // -1: Appel par SetMin
            if( iMaxLength == -1 )
                inherited::MaxLength ++;
            }
        }
        
    catch( Exception &e )
        {
        EICDisplayException( TAG(30), e );
        }
    }



//////////////////////////////////////
//
// SetMin
//
// Fonction: Initialise Min
//
// P.E.: Min
//
// P.S.: AUCUN
//
//////////////////////////////////////
void __fastcall CInNum::SetMin( double dMin )
    {
    FMin = dMin;

    if( dMin < 0 )
        MaxLength = -1;
    else
        MaxLength = 0;
    }



//////////////////////////////////////
//
// SetNSActive
//
// Fonction: Initialise NSActive
//
// P.E.: NSActive
//
// P.S.: AUCUN
//
//////////////////////////////////////
void __fastcall CInNum::SetNSActive( bool bNSActive )
    {
    FNSActive = bNSActive;
    }



//////////////////////////////////////
//
// SetText
//
// Fonction: Initialise Text
//
// P.E.: Text
//
// P.S.: AUCUN
//
//////////////////////////////////////
void __fastcall CInNum::SetText( const AnsiString aTextOrigin )
    {
    AnsiString  aText       = aTextOrigin;
    int         iPosSep    = 0;

    try
        {
        if(( iPosSep = aText.Pos(SEP_DEC)) != 0 )
            aText[iPosSep] = DecimalSeparator;
        else if(( iPosSep = aText.Pos(SEP_DEC_2)) != 0 )
            aText[iPosSep] = DecimalSeparator;

        if( ComponentState.Contains( csDesigning ))
            {
            if( IsNumValid( aText ))
                {
                inherited::Text = aText;
                if( !aText.IsEmpty())
                    FValeur = Concatene( aText ).ToDouble();
                else
                    FValeur = ValNS;
                }
            }
        else
            {
            inherited::Text = aText;
            if( !aText.IsEmpty() )
                FValeur         = Concatene( aText ).ToDouble();
            else
                FValeur = ValNS;
            }
        }
        
    catch( Exception &e )
        {
        EICDisplayException( TAG(40), e );
        }
    }



//////////////////////////////////////
//
// SetTypeVal
//
// Fonction: Initialise le type de Numeric utilise
//           ainsi que son Max et sa valeur NS
//
// P.E.: TypeVal
//
// P.S.: AUCUN
//
//////////////////////////////////////
void __fastcall CInNum::SetTypeVal( enum TypeVal eTypeValeur )
    {
    FTypeVal = eTypeValeur;

    switch( eTypeValeur )
        {
        case eShInt:
            {
            ValNS   = SH_NS;
            if( Mask.IsEmpty())
                FMax    = SHRT_MAX;
            break;
            }

        case eUShInt:
            {
            ValNS   = USH_NS;
            if( Mask.IsEmpty())
                FMax    = USHRT_MAX;
            break;
            }

        case eInt:
            {
            ValNS   = I_NS;
            if( Mask.IsEmpty())
                FMax    = INT_MAX;
            break;
            }

        case eUInt:
            {
            ValNS   = UI_NS;
            if( Mask.IsEmpty())
                FMax    = UINT_MAX;
            break;
            }

        case eLong:
            {
            ValNS   = L_NS;
            if( Mask.IsEmpty())
                FMax    = LONG_MAX;
            break;
            }

        case eFloat:
            {
            ValNS   = F_NS;
            if( Mask.IsEmpty())
                FMax    = MAXMAX;
            break;
            }

        case eDouble:
        case eCurrency:
            {
            ValNS   = D_NS;
            if( Mask.IsEmpty())
                Max     = MAXMAX;
            break;
            }

        default :
            {
            ValNS   = D_NS;
            if( Mask.IsEmpty())
                Max     = MAXMAX;
            }
        }
    }



//////////////////////////////////////
//
// SetValue
//
// Fonction: Initialise la valeur du Numeric
//
// P.E.: Valeur
//
// P.S.: AUCUN
//
//////////////////////////////////////
void __fastcall CInNum::SetValue( double dValeur )
    {
    if( IsNumValid( dValeur ))
        {
        FValeur = dValeur;
        inherited::Text = AnsiString( dValeur );
        }
    }



void __fastcall CInNum::SetValNS( double Value )
    {
    }


//////////////////////////////////////
//
// GetValue
//
// Fonction: Renvoie Valeur
//
// P.E.: AUCUN
//
// P.S.: Valeur
//
//////////////////////////////////////
double __fastcall CInNum::GetValue() const
    {
    return( FValeur );
    }



//////////////////////////////////////
//
// GetText
//
// Fonction: Renvoie Text
//
// P.E.: AUCUN
//
// P.S.: Text
//
//////////////////////////////////////
AnsiString __fastcall CInNum::GetText() /*const*/
    {
    return( inherited::Text );
    }



//////////////////////////////////////
//
//  GetMaxLength
//
// Fonction: Renvoie la longueur max du Num
//
// P.E.: AUCUN
//
// P.S.: MaxLength
//
//////////////////////////////////////
int __fastcall CInNum::GetMaxLength() /*const*/
    {
    return( inherited::MaxLength );
    }





//////////////////////////////////////
//
//
//
// Fonction:
//
// P.E.: AUCUN
//
// P.S.: AUCUN
//
//////////////////////////////////////
void __fastcall CInNum::KeyDown( Word &Key, Classes::TShiftState Shift )
    {
    AnsiString  aClip;
    AnsiString  aTmp        = Text;
    int         iNbDecims;
    int         iNbEntiers;
    int         PosDec;

    try
        {
        if( Shift.Contains( ssCtrl ))
            {
            switch( Key )
                {
                case 'C':
                case 'c':
                    {
                    CopyToClipboard();
                    break;
                    }
                case 'V':
                case 'v':
                    {
                    if( Clipboard()->HasFormat( CF_TEXT ))
                        {
                        aClip = Clipboard()->AsText;

                        if( !IsClipboardValid())
                            Key = VK_CANCEL;
                        else
                            SetSelTextBuf( aClip.c_str());
                        }
                    else
                        Key = VK_CANCEL;
                    break;
                    }
                }
            }

        if( Shift.Contains( ssShift ))
            Key = VK_CANCEL;

        switch( Key )
            {
            case VK_DELETE:
                {
                DecompNum( aTmp, iNbEntiers, iNbDecims, PosDec );
                if( PosDec && SelStart == PosDec - 1 )
                    {
                    aTmp.Delete( PosDec, 1 );
                    if( !IsNumValid( aTmp ))
                        Key = VK_CANCEL;
                    }
                else
                    {
                    aTmp.Delete( SelStart + 1, 1 );
                    if( aTmp.AnsiCompare( "-" ) == 0 )
                        break;
                    if( !IsNumValid( aTmp ))
                        Key = VK_CANCEL;
                    }
                break;
                }
            }

        inherited::KeyDown( Key, Shift );
        }

    catch( Exception &e )
        {
        EICDisplayException( TAG(50), e );
        }
    }



//////////////////////////////////////
//
//
//
// Fonction:
//
// P.E.: AUCUN
//
// P.S.: AUCUN
//
//////////////////////////////////////
void __fastcall CInNum::KeyPress( char &Key )
    {
    AnsiString aMask; //"99999.99";
    AnsiString aText    = Text;
    AnsiString Selection;
    AnsiString aTmp;
    int iNbDecim;   //Nombre de decimales du Mask
    int iNbEntier;
    int iNbDecimNum; //Nombre de decimales de l'EditNum
    int iNbEntierNum;

    int SizeMax;
    int PosDec;
    bool bSigned;



    try
        {
        // Test selection
        if( SelLength != 0 )
            {
            Selection   = SelText;
            SelText     = "";
            aText       = Text;
            }

        aMask   = FMask;
        SizeMax = aMask.Length();
        if( SizeMax == 0 )
            SizeMax = MAXMASK;

        // Calcul taille entier & decimal du Mask
        /////////////////////////////////////////
        DecompNum( aMask, iNbEntier, iNbDecim, PosDec );

        // Calcul taille entier & decimal de l'EditNum
        //////////////////////////////////////////////
        bSigned = DecompNum( aText, iNbEntierNum, iNbDecimNum, PosDec );
        if( bSigned )
            {
            iNbEntier ++;
            Font->Color = FColorNeg;
            }

        else
            Font->Color = clWindowText;
        }

    catch( Exception &e )
        {
        EICDisplayException( TAG(60), e );
        }

    try
        {
        switch( Key )
            {
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                {
                if( aText.Length() >= SizeMax && Min >= 0 )
                    Key = VK_CANCEL;
                else
                    {
                    if( !Mask.IsEmpty())
                        {
                        if( PosDec )
                            {
                            if( PosDec > iNbEntier && SelStart < iNbEntier + 1 )
                                Key = VK_CANCEL;
                            else if( SelStart >= PosDec && aText.Length() - PosDec >= iNbDecim )
                                Key = VK_CANCEL;
                            }
                        else if( SelStart >= iNbEntier || iNbEntierNum >= iNbEntier )
                            Key = VK_CANCEL;
                        if( SelStart == 0 && bSigned )
                            Key = VK_CANCEL;
                        if( Key != VK_CANCEL && !IsNumInMiddle( aText, Key ))
                            Key = VK_CANCEL;
                        }

                    else
                        {
                        if( bSigned && SelStart == 0 )
                            Key = VK_CANCEL;
                        }
                    }
                if( bSigned && aText.Length() == 1 && SelStart == 1 && Key == '0' )
                    Font->Color = clWindowText;
                break;
                }

            case SEP_DEC_2:
            case SEP_DEC:
                {
                Key = DecimalSeparator;
                
                if(( iNbDecim != 0 || Mask.IsEmpty()) && aText.Length() < SizeMax - 1 )
                    {
                    if( PosDec )
                        Key = VK_CANCEL;
                    }
                else
                    Key = VK_CANCEL;

                break;
                }

            case '-':
                {
                if( bSigned || SelStart != 0 || Min >= 0 )
                    Key = VK_CANCEL;
                else if( aText.AnsiCompare( "0" ) != 0 )
                    Font->Color = FColorNeg;
                break;
                }


            case VK_BACK:
                {
                if( PosDec && SelStart == PosDec )
                    {
                    aText.Delete( PosDec, 1 );
                    if( !IsNumValid( aText ))
                        Key = VK_CANCEL;
                    }
                break;
                }

            default:
                Key = VK_CANCEL;
            }

        if( Selection.Length() != 0 && Key == VK_CANCEL )
            {
            SelText     = Selection;
            SelStart   -= Selection.Length();
            }
        }

    catch( Exception &e )
        {
        EICDisplayException( TAG(70), e );
        }
    }


//////////////////////////////////////
//
//
//
// Fonction:
//
// P.E.: AUCUN
//
// P.S.: AUCUN
//
//////////////////////////////////////
AnsiString CInNum::Concatene( const AnsiString &aText )
    {
    int         i       = 0;
    int         iSize   = aText.Length();
    AnsiString  aTemp;
    char Car;

    while( i < iSize )
        {
        if((Car = aText.c_str()[i]) != ' ' )
            aTemp += AnsiString( Car );
        i ++;
        }
    return( aTemp );
    }



//////////////////////////////////////
//
//
//
// Fonction:
//
// P.E.: AUCUN
//
// P.S.: AUCUN
//
//////////////////////////////////////
AnsiString CInNum::Format( const AnsiString &aText, const AnsiString &aMask ) 
    {
    int         iSize;
    int         i;
    int         iCnt        = 0;
    int         NbDecimales;
    int         iNbEntiers;
    int         PosDec;
    AnsiString  aFinal;
    AnsiString  aTemp       = aText;

    try
        {
        if( aTemp.IsEmpty())
            return( AnsiString(""));

        aTemp   = Concatene( aTemp );

        DecompNum( aMask, iNbEntiers, NbDecimales, PosDec );

        if(!aMask.IsEmpty())
            aTemp   = (double)Round(aTemp.ToDouble(), NbDecimales);
        iSize   = aTemp.Length() - 1;

        PosDec  = aTemp.Pos( AnsiString( DecimalSeparator ));
        if( PosDec != 0 )
            {
            aFinal = aTemp.SubString( PosDec, aTemp.Length() - PosDec + 1 );
            if( NbDecimales >= aFinal.Length())
                aFinal += AnsiString( "00000000000" ).SubString( 1, NbDecimales+1 - aFinal.Length());
            i = PosDec - 2;
            }
        else
            {
            if( NbDecimales != 0 )
                {
                aFinal += AnsiString( DecimalSeparator );
                aFinal += AnsiString( "0000000" ).SubString( 1, NbDecimales );
                }
            i = iSize;
            }

        // Ajoute les separateurs de milliers
        /////////////////////////////////////
        while( i >= 0 )
            {
            if( iCnt %3 == 0 && iCnt != 0 )
                {
                if( !( i == 0 && aTemp.c_str()[ 0 ] == '-' ))
                    aFinal.Insert( " ", 0 );
                }
            aFinal.Insert( aTemp.c_str()[ i ], 0 );
            iCnt ++;
            i --;
            }
         }

    catch( Exception &e )
        {
        EICDisplayException( TAG(80), e );
        }
    return( aFinal );
    }

//////////////////////////////////////
//
//
//
// Fonction:
//
// P.E.: AUCUN
//
// P.S.: AUCUN
//
//////////////////////////////////////
bool __fastcall CInNum::IsClipboardValid()
    {
    AnsiString  aClip;
    AnsiString  aTemp           = Text;
    int         OldStart        = SelStart;

    try
        {
        // Lecture du Clipboard
        aClip = Clipboard()->AsText;

        // Suppression des car selectionnes pour remplacement
        if( SelLength != 0 )
            aTemp.Delete( OldStart + 1, SelLength );

        // Insertion du Clip dans Text temporaire
        aTemp.Insert( aClip, OldStart + 1 );

        // Tests approfondis
        return( IsNumValid( aTemp ));
        }

    catch( Exception &e )
        {
        EICDisplayException( TAG(100), e );
        }
    return( true );
    }



bool __fastcall CInNum::IsNumValid( const AnsiString &aNum )
    {

    AnsiString  aTemp;
    int         i               = 0;
    bool        bCntEntiers     = true; // flag pour comptage des entiers / decimales
    int         iNbEntiers      = 0;
    signed int  iNbDecim        = -1;
    int         iNbPtsDecim     = 0; // nb de pts decimaux
    int         iMaskNbEntiers;
    int         iMaskNbDecim;
    int         PosDec;
    bool        bSigned         = false;
    AnsiString  aValidCars( "0123456789.,- " );

    bIsNumValid = false;

    try
        {
        if( aNum.IsEmpty())
            {
            if( NSActive )
                {
                bIsNumValid = true;
                return( true );
                }
            else
                return( false );
            }

        while( i < aNum.Length())
            {
            // Test si caracteres numeriques
            aTemp = aNum.c_str()[i];
            if((signed)strcspn( aTemp.c_str(), aValidCars.c_str()) == aTemp.Length())
                return( false );

            if( aNum.c_str()[ i ] == DecimalSeparator )
                {
                bCntEntiers = false;
                iNbPtsDecim ++;
                if( iNbPtsDecim > 1 )
                    return( false );
                }
            else if( aNum.c_str()[ i ] == '-' )
                {
                if( bSigned )
                    return( false );
                bSigned = true;
                break;
                }
            if( bCntEntiers )
                iNbEntiers ++;
            else
                iNbDecim ++;

            i ++;
            }

        // Calcul taille entier & decimal du Mask
        /////////////////////////////////////////
        DecompNum( Mask, iMaskNbEntiers, iMaskNbDecim, PosDec );

        if( iNbEntiers > iMaskNbEntiers || iNbDecim > iMaskNbDecim )
            return( false );

        // Test d'aapartenance aux valeurs Min et Max imposees
        if( aNum.ToDouble() < Min || aNum.ToDouble() > Max )
            return( false );

        if( bSigned && aNum.Length() == 2 && aNum.c_str()[ 1 ] == '0' )
            Font->Color = clWindowText;
        else if( bSigned )
            Font->Color = FColorNeg;
        else
            Font->Color = clWindowText;

        bIsNumValid = true;
        }

    catch( Exception &e )
        {
        EICDisplayException( TAG(110), e );
        }
        
    return( true );
    }



//////////////////////////////////////
//
//
//
// Fonction:
//
// P.E.: AUCUN
//
// P.S.: AUCUN
//
//////////////////////////////////////
bool __fastcall CInNum::IsNumInMiddle( const AnsiString &aText, char Key )
    {
    AnsiString  aTmp        = aText;
    AnsiString  aMax;
    AnsiString  aMin;
    AnsiString  a1;
    AnsiString  a2;
    int         iNbEntiers;
    int         iNbDecim;
    int         iMaxNbEntiers;
    int         iMaxNbDecim;
    int         PosDec;
    int         PosDecMax;

    try
        {
        aTmp.Insert( Key, SelStart + 1 );
        aMax = Max;

        aMax = Concatene( Format( aMax, Mask ));

        DecompNum( aTmp, iNbEntiers, iNbDecim, PosDec );
        DecompNum( aMax, iMaxNbEntiers, iMaxNbDecim, PosDecMax );

        if( iNbEntiers > iMaxNbEntiers )
            return( false );

        else if( iNbEntiers == iMaxNbEntiers )
            {
            a1 = aTmp.SubString( 1, iNbEntiers ).ToDouble();
            a2 = aMax.SubString( 1, iNbEntiers ).ToDouble();
            if( a1 > a2 )
                return( false );
            else if( a1 == a2 )
                {
                if( PosDec != 0 )
                    {
                    a1 = aTmp.SubString( PosDec, iNbDecim ).ToDouble();
                    a2 = aMax.SubString( PosDec, iNbDecim ).ToDouble();
                    if( a1 > a2 )
                        return( false );
                    }
                }
            }
        }
        
    catch( Exception &e )
        {
        EICDisplayException( TAG(120), e );
        }
    return( true );
    }



//////////////////////////////////////
//
// WndProc
//
// Fonction: Capture les messages
//
// P.E.: Les messages
//
// P.S.: AUCUN
//
//////////////////////////////////////
void __fastcall CInNum::WndProc( TMessage &Message )
    {
    static bool bFlagExec = true;

    try
        {
        switch( Message.Msg )
            {
            case WM_SETFOCUS:
                {
                if( Text.AnsiCompare("-") != 0 )
                    {
                    if( NSActive && FValeur == ValNS )
                        Text = "";
                    else
                        Text = Concatene( Text );
                    }
                SelectAll();
                break;
                }

            case WM_NCPAINT:
                {
                if( !ComponentState.Contains( csDesigning ) && bFlagExec )
                    {
                    Text        = Format( Text, Mask );
                    bFlagExec   = false;
                    }
                break;
                }

            case WM_PASTE:
                {
                if( Clipboard()->HasFormat( CF_TEXT ))
                    {
                    if( !IsClipboardValid())
                        Message.Msg = WM_NULL;
                    }
                else
                    Message.Msg = WM_NULL;
                break;
                }

            case WM_KILLFOCUS:
                {
                Text = Concatene( Text );
                if( !Text.IsEmpty() && ( Text.AnsiCompare("-" ) == 0 || Text.ToDouble() < Min ))
                    {
                    bIsNumValid = false;
                    Message.Msg = WM_NULL;
                    ::SetFocus( Handle );
                    }
                else
                    {
                    if( Text.IsEmpty())
                        {
                        if( NSActive )
                            FValeur = ValNS;
                        else
                            {
                            Valeur  = 0;
                            Text    = Format( Text, Mask );
                            }
                        }
                    else
                        Text = Format( Text, Mask );

                    bIsNumValid = true;
                    }

                if( Message.Msg != WM_NULL )
                   {
//                   ((CStringGrid*)Parent)->SetCell( Text );
                   Hide(); //Lorsque le composant perd le focus, on le cache
                  }
                break;
                }
            }
        }
    catch( Exception &e )
        {
        EICDisplayException( TAG(130), e );
        }
    inherited::WndProc( Message );
    }




///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////


static inline void ValidCtrCheck(CStringGrid *)
    {
    new CStringGrid(NULL);
    }



__fastcall CStringGrid::CStringGrid(TComponent* Owner)
    : TCustomGrid(Owner)
    {
    int i = 0;

    CInEditor           = NULL;
    DefaultDrawing      = false;
    FCellCurColText     = clBlack;
    FCellCurColBkGrnd   = clGrayText;
    FReadOnly           = false;
    bRowAutoSize        = true;
    bColAutoSize        = true;
    Options<<goEditing<<goTabs;
    DefaultRowHeight    = 21;
    FAlignFixedCols     = TAlCenter;
    FAlignFixedRows     = TAlRight;
    LastColActive       = -1;
    LastRowActive       = -1;
    bEditorAlpha        = false;

    try
        {
        while( i < ECUNoUnit )
            {
            BmpColUnit[ i ]                 = new Graphics::TBitmap();
            BmpColUnit[ i ]->Transparent    = true;
            i ++;
            }

        BmpColUnit[ 0 ]->LoadFromResourceName((int)HInstance, "SYM_FRF" );
        BmpColUnit[ 1 ]->LoadFromResourceName((int)HInstance, "SYM_EUR" );
        BmpColUnit[ 2 ]->LoadFromResourceName((int)HInstance, "SYM_PERCENT" );

        Columns = new TStringList();
        CreateColumns();
        ColCount = 8;
        RowCount = 10;
//        CreateEditor();
        }

    catch( Exception &e )
        {
        i = 0;
        while( i < ECUNoUnit )
            {
            BmpColUnit[ i ] = new Graphics::TBitmap();
            BmpColUnit[ i ] = NULL;
            i ++;
            }
        EICDisplayException( TAG(140), e );
        }
    }

__fastcall CStringGrid::~CStringGrid()
{
  int i = 0;

  FreeColumns();
  delete Columns;

  while( i < ECUNoUnit )
      {
      delete BmpColUnit[ i ];
      i ++;
      }
}

void __fastcall CStringGrid::SetAlignFixedCols( enum TTextAlign AlFixedCols )
    {
    FAlignFixedCols = AlFixedCols;
    Repaint();
    }

void __fastcall CStringGrid::SetAlignFixedRows( enum TTextAlign AlFixedRows )
    {
    FAlignFixedRows = AlFixedRows;
    Repaint();
    }



void __fastcall CStringGrid::SetColCount( int iColCount )
    {
    FreeColumns();

    inherited::ColCount = iColCount;
    if( iColCount > 1 && inherited::FixedCols == 0 )
        inherited::FixedCols = 1;

    CreateColumns();
    }



void __fastcall CStringGrid::SetReadOnly( bool bReadOnly )
    {
    FReadOnly = bReadOnly;

    if( bReadOnly )
        Options>>goEditing;
    else
        Options<<goEditing;

    Color = bReadOnly ? clBtnFace : clWindow;     
    }




void __fastcall CStringGrid::SetRowCount( int iRowCount )
    {
    FreeRows();

    inherited::RowCount = iRowCount;
    if( iRowCount > 1 && inherited::FixedRows == 0 )
        inherited::FixedRows = 1;

    CreateRows();
    }


int __fastcall CStringGrid::GetColCount() const
    {
    return( inherited::ColCount );
    }


int __fastcall CStringGrid::GetRowCount() const
    {
    return( inherited::RowCount );
    }

TInplaceEdit* __fastcall CStringGrid::CreateEditor(void)
    {
    if(CInEditor)
       {
       delete CInEditor;
       CInEditor = NULL;
       }
    try
        {
        if( !bEditorAlpha )
            CInEditor           = new CInNum( this );
        else
            CInEditor           = new CIn( this );
        CInEditor->Parent       = this;
        }

    catch( Exception &e )
        {
        EICDisplayException( TAG(150), e );
        }

    return( CInEditor );
    }

bool __fastcall CStringGrid::CanEditShow(void)
{
return inherited::CanEditShow() && (InplaceEditor && InplaceEditor->Focused() || Focused());
}

void    __fastcall CStringGrid::SetCellCurColText( TColor CColor )
    {
    FCellCurColText         = CColor;
    Repaint();
    }

void    __fastcall CStringGrid::SetCellCurColBkGrnd( TColor CColor )
    {
    FCellCurColBkGrnd       = CColor;
    Repaint();
    }

System::AnsiString __fastcall CStringGrid::GetEditText(int ACol, int ARow)
    {
    LastColActive = ACol;
    LastRowActive = ARow;

    try
        {
        ((CInNum *)CInEditor)->Mask        = Columns->Strings[Col];
        ((CInNum *)CInEditor)->TypeValeur  = ColType[Col];
        return ((TStringList *)Columns->Objects[ACol])->Strings[ARow];
        }

   catch( Exception &e )
        {
        EICDisplayException( TAG(160), e );
        }
    return( NULL );
    }

/*******************************************************************************

Fonction :

Paramètres d'entrée :

Paramètres modifiés :

Valeur retournée :
*******************************************************************************/
void __fastcall CStringGrid::SetEditText(int ACol, int ARow, const System::AnsiString Value)
    {
    try
        {
        if (ACol < ColCount && ARow < RowCount)
           ((TStringList *)Columns->Objects[ACol])->Strings[ARow] = Value;
        }
    catch( Exception &e )
        {
        EICDisplayException( TAG(170), e );
        }
    }

/*******************************************************************************

Fonction :

Paramètres d'entrée :

Paramètres modifiés :

Valeur retournée :
*******************************************************************************/
void __fastcall CStringGrid::DrawCell( int Col, int Row, const Windows::TRect &Rect, TGridDrawState State)
    {
    int iState;

    if( State.Contains( gdSelected ))
        iState = gdSelected;
    else if( State.Contains( gdFocused ))
        iState = gdFocused;
    else iState = gdFixed;


    switch( iState )
        {
        case gdSelected :
        case gdFocused:
            {
            FillRectFocused( Rect, Col, Row );
            break;
            }

        case gdFixed:
            {
            FillRectFixed( Rect, Col, Row );
            break;
            }
        }
    }



void __fastcall CStringGrid::FillRectFocused( TRect Rect, int iCol, int iRow )
    {
    DrawCellSimple( Rect, iCol, iRow, CellCurColBkGrnd, CellCurColText );
    }



void __fastcall CStringGrid::FillRectFixed( TRect Rect, int iCol, int iRow )
    {
    if( iRow < FixedRows  || iCol < FixedCols )
        DrawCell3D( Rect, iCol, iRow );
    else
        DrawCellSimple( Rect, iCol, iRow, Color, Font->Color );
    }



void __fastcall CStringGrid::DrawCell3D( TRect Rect, int iCol, int iRow )
    {
    Canvas->Brush->Color    = FixedColor;
    Canvas->Pen->Color      = FixedColor;
    Canvas->Rectangle( Rect.Left, Rect.Top, Rect.Right, Rect.Bottom );

    Canvas->Pen->Color      = clBtnShadow;
    Canvas->MoveTo( Rect.Right - 1, Rect.Top        + 1 );
    Canvas->LineTo( Rect.Right - 1, Rect.Bottom     - 1 );
    Canvas->LineTo( Rect.Left,      Rect.Bottom     - 1 );

    Canvas->Pen->Color      = clBtnHighlight;
    Canvas->LineTo( Rect.Left,      Rect.Top);
    Canvas->LineTo( Rect.Right,     Rect.Top );

    AlignText( Rect, iCol, iRow, clBlack );
    }


void __fastcall CStringGrid::DrawCellSimple( TRect Rect, int iCol, int iRow, TColor ColorBkGrnd, TColor ColorText )
    {
    int iIndiceBmp;
    AnsiString aColTitle    = ((TStringList *)Columns->Objects[ iCol ])->Strings[ 0 ];

    if (!aColTitle.IsEmpty())
       iIndiceBmp = aColTitle[ aColTitle.Length()] - '0';
    else
       iIndiceBmp = -1;

    Canvas->Brush->Color    = ColorBkGrnd;
    Canvas->Pen->Color      = ColorBkGrnd;
    Canvas->Rectangle( Rect.Left, Rect.Top, Rect.Right, Rect.Bottom );

    if( FDrawUnit && iIndiceBmp > -1 && iIndiceBmp < ECUNoUnit )
        Canvas->Draw( Rect.Right - 11, Rect.Top + ( Rect.Bottom - Rect.Top - 10 ) / 2, BmpColUnit[iIndiceBmp] );

    AlignText( Rect, iCol, iRow, ColorText );
    }




void __fastcall CStringGrid::AlignText( TRect Rect, int iCol, int iRow, TColor ColorText )
    {
    int             Pos;
    enum TTextAlign CellAlign1;
    enum TTextAlign CellAlign2;
    AnsiString      aTemp1;
    AnsiString      aTemp2;
    AnsiString      aCell;
    enum TTextAlign AlignCol    = ColAlign[ iCol ];


    try
        {
        if( iCol >= FixedCols && iRow >= FixedRows )
            aCell   = CInNum::Format(((TStringList *)Columns->Objects[iCol])->Strings[ iRow ],
                                     Columns->Strings[iCol]);
        else
            {
            aCell   = ((TStringList *)Columns->Objects[ iCol ])->Strings[ iRow ];
            if( iCol >= FixedCols )
                aCell = aCell.SubString( 1, aCell.Length() - 1 );
            }

        if(( Pos = aCell.Pos("\n")) != 0 )
            {
            aTemp1 = aCell.SubString( 1, Pos-1 );
            aTemp2 = aCell.SubString( Pos+1, aCell.Length() - Pos );

            if( iRow >= FixedRows && iCol >= FixedCols && ( AlignCol == 0 || AlignCol == 3 || AlignCol == 6 ))
                {
                CellAlign1 = TAlLeftTop;
                CellAlign2 = TAlLeftBottom;
                }

            else if( iRow < FixedRows && ( FAlignFixedCols == 0 || FAlignFixedCols == 3 || FAlignFixedCols == 6 ))
                {
                CellAlign1 = TAlLeftTop;
                CellAlign2 = TAlLeftBottom;
                }

            else if( iRow >= FixedRows && iCol < FixedCols && ( AlignCol == 0 || AlignCol == 3 || AlignCol == 6 ))
                {
                CellAlign1 = TAlLeftTop;
                CellAlign2 = TAlLeftBottom;
                }

            else if( iRow >= FixedRows && iCol >= FixedCols && ( AlignCol == 1 || AlignCol == 4 || AlignCol == 7 ))
                {
                CellAlign1 = TAlCenterTop;
                CellAlign2 = TAlCenterBottom;
                }

            else if( iRow >= FixedRows && iCol < FixedCols && ( AlignCol == 1 || AlignCol == 4 || AlignCol == 7 ))
                {
                CellAlign1 = TAlCenterTop;
                CellAlign2 = TAlCenterBottom;
                }

            else if( iRow < FixedRows && ( FAlignFixedCols == 1 || FAlignFixedCols == 4 || FAlignFixedCols == 7 ))
                {
                CellAlign1 = TAlCenterTop;
                CellAlign2 = TAlCenterBottom;
                }

            else
                {
                CellAlign1 = TAlRightTop;
                CellAlign2 = TAlRightBottom;
                }

            if( bRowAutoSize )
                {
                if( RowHeights[ iRow ] < ROW_HEIGHT_DOUBLE_MINI )
                    RowHeights[ iRow ] = ROW_HEIGHT_DOUBLE_MINI;
                }

            AffiText( Rect, iCol, iRow, CellAlign1, aTemp1, ColorText );
            AffiText( Rect, iCol, iRow, CellAlign2, aTemp2, ColorText );
            }

        else
            {
            if( iRow < FixedRows )
                AffiText( Rect, iCol, iRow, FAlignFixedCols, aCell, ColorText );
            else
                AffiText( Rect, iCol, iRow, AlignCol, aCell, ColorText );
            }
        }

    catch( Exception &e )
        {
        EICDisplayException( TAG(180), e );
        }
    }



void __fastcall CStringGrid::AffiText( TRect Rect, int iCol, int iRow, enum TTextAlign TAlign, AnsiString aText, TColor ColorText )
    {
    int         iLeft;
    int         iTop;
    int         ColWidth;

    if( bColAutoSize && iRow < FixedRows )
        {
        if(( ColWidth = Canvas->TextWidth( aText )) >= ColWidths[ iCol ] )
            ColWidths[ iCol ] = ColWidth + CELL_LEFT_MINI + CELL_RIGHT_MINI + 10;
        else if( ColWidth < DefaultColWidth && ColWidths[ iCol ] < DefaultColWidth )
            ColWidths[ iCol ] = DefaultColWidth;
        }

    switch( TAlign )
        {
        case TAlLeftTop:
            {
            iLeft   = Rect.Left     + CELL_LEFT_MINI;
            iTop    = Rect.Top      + CELL_TOP_MINI;
            break;
            }
        case TAlCenterTop:
            {
            iLeft   = ( Rect.Right  - Rect.Left - Canvas->TextWidth( aText )) / 2 + Rect.Left;
            iTop    = Rect.Top      + CELL_TOP_MINI;
            break;
            }
        case TAlRightTop:
            {
            iLeft   = Rect.Right    - Canvas->TextWidth( aText )    - CELL_RIGHT_MINI;
            iTop    = Rect.Top      + CELL_TOP_MINI;

            if( FDrawUnit )
                iLeft -= 13;
            break;
            }
        case TAlLeft:
            {
            iLeft   = Rect.Left     + CELL_LEFT_MINI;
            iTop    = ( Rect.Bottom - Rect.Top  - Canvas->TextHeight( aText )) / 2 + Rect.Top;
            break;
            }
        case TAlCenter:
            {
            iLeft   = ( Rect.Right  - Rect.Left - Canvas->TextWidth(  aText )) / 2 + Rect.Left;
            iTop    = ( Rect.Bottom - Rect.Top  - Canvas->TextHeight( aText )) / 2 + Rect.Top;
            break;
            }
        case TAlRight:
            {
            iLeft   = Rect.Right    - Canvas->TextWidth( aText )    - CELL_RIGHT_MINI;
            iTop    = ( Rect.Bottom - Rect.Top  - Canvas->TextHeight( aText )) / 2 + Rect.Top;
            if( FDrawUnit )
                iLeft -= 13;
            break;
            }
        case TAlLeftBottom:
            {
            iLeft   = Rect.Left     + CELL_LEFT_MINI;
            iTop    = Rect.Bottom   - Canvas->TextHeight( aText )   - CELL_BOT_MINI;
            break;
            }
        case TAlCenterBottom:
            {
            iLeft   = ( Rect.Right  - Rect.Left - Canvas->TextWidth( aText )) / 2 + Rect.Left;
            iTop    = Rect.Bottom   - Canvas->TextHeight( aText )   - CELL_BOT_MINI;
            break;
            }
        case TAlRightBottom:
            {
            iLeft   = Rect.Right    - Canvas->TextWidth(  aText )   - CELL_RIGHT_MINI;
            iTop    = Rect.Bottom   - Canvas->TextHeight( aText )   - CELL_BOT_MINI;
            if( FDrawUnit )
                iLeft -= 13;
            break;
            }

        default:
            {
            break;
            }
        }

    Canvas->Font->Style<<fsBold<<fsStrikeOut;
    Canvas->Font->Color = ColorText;
    Canvas->TextOut( iLeft, iTop, aText );
    }



void __fastcall CStringGrid::CreateColumns()
    {
    int i = 0;

    while( i < ColCount )
        {
        CreateColumn();
        i ++;
        }

    CreateRows();
    }


void __fastcall CStringGrid::CreateColumn()
    {
    try
        {
        Columns->AddObject(EmptyStr, new TStringList);
        }

    catch( Exception &e )
        {
        EICDisplayException( TAG(190), e );
        }
    }



void __fastcall CStringGrid::ClearGrid()
    {
    int i = 0;

    while( i < ColCount )
        {
        ClearColumn( i );
        i ++;
        }
    }



void __fastcall CStringGrid::ClearColumn( int iCol )
    {
    int i = 0;

    try
        {
        while( i < RowCount )
            {
            ((TStringList *)Columns->Objects[ iCol ])->Strings[ i ] = EmptyStr;
            i ++;
            }
        }

    catch( Exception &e )
        {
        EICDisplayException( TAG(200), e );
        }
    }


void __fastcall CStringGrid::FreeColumns()
    {
    int i = inherited::ColCount;

    try
        {
        while( i > 0 )
            {
            Columns->Objects[ i - 1 ]->Free();
            Columns->Delete( i - 1 );
            i --;
            }
        }

    catch( Exception &e )
        {
        EICDisplayException( TAG(210), e );
        }
    }



void __fastcall CStringGrid::FreeColumn( int iCol )
    {
    try
       {
       Columns->Objects[ iCol ]->Free();
       Columns->Delete( iCol );
       }

    catch( Exception &e )
        {
        EICDisplayException( TAG(220), e );
        }
    }


void __fastcall CStringGrid::CreateRows()
    {
    int i = 0;

    while( i < inherited::RowCount )
        {
        CreateRow();
        i ++;
        }
    }


void __fastcall CStringGrid::CreateRow()
    {
    int i = 0;

    try
        {
        while( i < inherited::ColCount )
            {
            ((TStringList*)Columns->Objects[ i ])->Add("");
            i ++;
            }
        }

    catch( Exception &e )
        {
        EICDisplayException( TAG(230), e );
        }
    }


void __fastcall CStringGrid::FreeRows()
    {
    signed int i = inherited::RowCount;

    while( i > 0 )
        {
        FreeRow( i - 1 );
        i --;
        }
    }



void __fastcall CStringGrid::FreeRow( int iRow )
    {
    signed int i = inherited::ColCount;

    try
        {
        while( i > 0 )
            {
            ((TStringList *)Columns->Objects[i-1])->Delete( iRow );
            i --;
            }
        }

    catch( Exception &e )
        {
        EICDisplayException( TAG(240), e );
        }
    }



void __fastcall CStringGrid::SetCell(AnsiString aValue )
    {
    try
        {
        if( LastColActive != -1 && LastRowActive != -1 )
            ((TStringList *)Columns->Objects[LastColActive])->Strings[LastRowActive] = aValue;
        }

    catch( Exception &e )
        {
        EICDisplayException( TAG(250), e );
        }

    if (InplaceEditor && InplaceEditor->PosEqual(CellRect(LastColActive, LastRowActive)))
       InplaceEditor->Text = GetEditText(LastColActive, LastRowActive);
    }

void __fastcall CStringGrid::SetCell( int iCol, int iRow, AnsiString aValue, bool bFixed )
    {
    try
        {
        if(!bFixed)
           ((TStringList *)Columns->Objects[iCol + FixedCols])->Strings[iRow + FixedRows] = CInNum::Format(aValue, Columns->Strings[iCol + FixedCols]);
        else
           ((TStringList *)Columns->Objects[ iCol ])->Strings[ iRow ] = aValue;
        }

    catch( Exception &e )
        {
        EICDisplayException( TAG(260), e );
        }

    InvalidateCell( iCol, iRow );

    if (InplaceEditor && InplaceEditor->PosEqual(CellRect(iCol + (bFixed ? 0 : FixedCols), iRow + (bFixed ? 0 : FixedRows))))
       InplaceEditor->Text = GetEditText(iCol + (bFixed ? 0 : FixedCols), iRow + (bFixed ? 0 : FixedRows));
    }




void __fastcall CStringGrid::SetCell( int iCol, int iRow, double dValue, bool bFixed )
    {
    try
        {
        if( !bFixed )
            ((TStringList *)Columns->Objects[iCol + FixedCols])->Strings[iRow + FixedRows] =  CInNum::Format(dValue, Columns->Strings[iCol + FixedCols]);
        else
            ((TStringList *)Columns->Objects[ iCol ])->Strings[ iRow ] = dValue;
        }

    catch( Exception &e )
        {
        EICDisplayException( TAG(270), e );
        }

    InvalidateCell( iCol, iRow );

    if (InplaceEditor && InplaceEditor->PosEqual(CellRect(iCol + (bFixed ? 0 : FixedCols), iRow + (bFixed ? 0 : FixedRows))))
       InplaceEditor->Text = GetEditText(iCol + (bFixed ? 0 : FixedCols), iRow + (bFixed ? 0 : FixedRows));
    }


AnsiString __fastcall CStringGrid::GetCell( int iCol, int iRow, bool bFixed ) const
    {
    try
        {
        if( !bFixed )
            return(CInNum::Concatene(((TStringList *)Columns->Objects[ iCol + FixedCols ])->Strings[ iRow + FixedRows ] ));
        else
            return(CInNum::Concatene(((TStringList *)Columns->Objects[ iCol ])->Strings[iRow]));
        }
    catch( Exception &e )
        {
        EICDisplayException( TAG(280), e );
        }
    return( NULL );
    }



void __fastcall CStringGrid::InitColumn( int iCol, const AnsiString &aTitle, const AnsiString &aMask,
    enum TypeVal eTypeVal, enum TTextAlign eTAlign, int iColWidth, enum ColUnit CUnit )
    {
    try
        {
        //Correction d'un bug => Dans les taux et plafonds, on modifie un taux (1e ligne, 1e colonne)
        //On clic sur le bouton de report de taux, on change d'écran de taux, on clic sur la
        //cellule se trouvant au même endroit => c'est la valeur du taux précédant qui apparaît. 
        HideEditor();
        ShowEditor();

        ClearColumn( iCol );
        Columns->Strings[iCol]                                  = aMask;
        ((TStringList *)Columns->Objects[ iCol ])->Strings[ 0 ] = aTitle + AnsiString((int)CUnit);
        ColType[ iCol ]                                         = eTypeVal;
        ColAlign[ iCol ]                                        = eTAlign;
        ColWidths[ iCol ]                                       = iColWidth;
        InvalidateCol( iCol );
        }
    catch( Exception &e )
        {
        EICDisplayException( TAG(290), e );
        }
    }

/*******************************************************************************

Fonction :

Paramètres d'entrée :

Paramètres modifiés :

Valeur retournée :
*******************************************************************************/
void __fastcall CStringGrid::WndProc( TMessage &Message )
    {
    switch( Message.Msg )
        {
        case WM_ENABLE:
            Enabled = (bool)Message.WParam;
            break;

        case WM_READONLY:
            ReadOnly = (bool)Message.WParam;
            break;
        }

    inherited::WndProc( Message );
    }

namespace Cstrgrid
    {
    void __fastcall PACKAGE Register()
        {
        TComponentClass classes[1] = {__classid(CStringGrid)};
        RegisterComponents("EIC Ctrlstd", classes, 0);
        }
    }

